package com.lw.controller;

import ch.qos.logback.core.util.StringUtil;
import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.secure.SaSecureUtil;
import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.stp.parameter.SaLoginParameter;
import cn.dev33.satoken.temp.SaTempTemplate;
import cn.dev33.satoken.temp.SaTempUtil;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import cn.hutool.captcha.generator.MathGenerator;
import cn.hutool.captcha.generator.RandomGenerator;
import cn.hutool.extra.template.TemplateConfig;
import cn.hutool.extra.template.TemplateEngine;
import cn.hutool.extra.template.TemplateUtil;
import com.lw.common.aop.LogOperation;
import com.lw.common.enums.LogModuleEnum;
import com.lw.common.utils.*;
import com.lw.common.vo.LoginVo;
import com.lw.entity.TbUser;
import com.lw.service.TbUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.web.bind.annotation.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * 首页提示
 * 注意:项目中命名规则有讲究 [Tb]是数据库表的前缀，[User]是表名，[Controller]是控制器
 * 否则 IndexController 是自定义[Controller] 没有对应的表
 */
@Tag(name = "00-登录管理/首页")
@RestController
@RequestMapping("index")
public class IndexController {
    @Resource
    TbUserService tbUserService;

    @Resource
    LoginAttemptService loginAttemptService;

    @GetMapping("/")
    @Operation(summary = "首页", description = "访问首页")
    @SaIgnore
    public ResultVo<String> index() {
        String tips = "你好，renren-admin已启动，请启动renren-ui，才能访问页面！";
        return ResultVo.success(tips);
    }

    @SaIgnore
    @PostMapping("login")
    @Operation(summary = "登录", description = "用户登录接口")
    @LogOperation(module = LogModuleEnum.LOG_LOGIN, value = "登录", params = false)
    public ResultVo<SaTokenInfo> login(@RequestBody LoginVo loginVo) {
        //1.验证码校验
        String captchaKey = loginVo.getCaptchaKey();
        if (StrUtils.isEmpty(captchaKey)) {
            return ResultVo.error("验证码KEY不能为空");
        }
        if (StringUtil.isNullOrEmpty(loginVo.getCaptchaCode())) {
            return ResultVo.error("验证码不能为空");
        }
        String captchaCode = loginVo.getCaptchaCode();
        //检查验证码校验是否过期
        long timeout = SaTempUtil.getTimeout(captchaKey);
        if (timeout <= 0) {
            return ResultVo.error("抱歉,验证码已过期,请重新刷新,新验证码时效为:60秒");
        }
        //验证码校验是否正确
        String captchaCodeCache = SaTempUtil.parseToken(captchaKey, String.class);
        String captchaKeyDecode = SaSecureUtil.aesDecrypt(GlobalConstants.SA_KEY, captchaCodeCache);  //解密验证码key
        if (!captchaCode.equalsIgnoreCase(captchaKeyDecode)) {
            return ResultVo.error("验证码错误");
        }

        //2.登录校验
        if (StringUtil.isNullOrEmpty(loginVo.getUsername()) || StringUtil.isNullOrEmpty(loginVo.getPassword())) {
            return ResultVo.error("用户名或密码不能为空");
        }
        TbUser user = tbUserService.getByUserName(loginVo.getUsername());

        //用户不存在
        if (user == null) {
            throw new RuntimeException("无该用户");
        }

        //密码错误
        if (!BCrypt.checkpw(loginVo.getPassword(), user.getPassword())) { //加密方式: BCrypt.hashpw(loginVo.getPassword(), BCrypt.gensalt(12));
            loginAttemptService.loginFailed(loginVo.getUsername());
            throw new RuntimeException("密码错误，您还有：" + loginAttemptService.hasTimes(loginVo.getUsername())+ "次机会");
        }

        //账号停用
        if (!user.getStatus()) {
            throw new RuntimeException("账户已经禁止使用");
        }
        //登录成功
        StpUtil.login(user.getId(),loginVo.getRememberMe());
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
        //登录成功后删除验证码临时存储的key
        SaTempUtil.deleteToken(captchaKey);
        return ResultVo.success(tokenInfo);
    }

    //登录页-验证码（有效期：60秒）
    @SaIgnore
    @GetMapping("captcha")
    @Operation(summary = "验证码", description = "获取验证码")
    public ResultVo<LoginVo> captcha() {
        LoginVo loginVo = new LoginVo();
        //定义图形验证码的长、宽、验证码字符数、干扰线宽度
        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(150, 40, 22, 3, 0.8F);
        // 定义验证码的字体   字体大小  字体颜色  背景颜色  干扰线颜色
        RandomGenerator randomGenerator = new RandomGenerator(GlobalConstants.CAPTCHA, 4);
        captcha.setGenerator(randomGenerator);
        // 生成验证码code
        captcha.createCode();

        //转换为字符串Base64编码，给前端渲染。
        String imageBase64Data = captcha.getImageBase64Data();
        loginVo.setCaptchaCode(imageBase64Data);
        String code = captcha.getCode();

        //设置验证码过期时间，默认：60秒
        String tokenCode = SaTempUtil.createToken(SaSecureUtil.aesEncrypt(GlobalConstants.SA_KEY, code), 60);
        loginVo.setCaptchaKey(tokenCode);
        return ResultVo.success(loginVo);
    }

    @DeleteMapping("logout")
    @Operation(summary = "退出登录", description = "退出登录")
    @LogOperation(module = LogModuleEnum.LOG_LOGIN, value = "退出登录", params = false)
    public ResultVo<String> logout() {
        StpUtil.logout();
        return ResultVo.success("退出成功");
    }


    @Autowired
    private CacheManager cacheManager;

    /**
     * 测试缓存
     * 检查缓存是否存在,经典案例
     * by lw on 二〇二五年五月二十八日 14:33:38
     * caffeine 缓存使用
     */
    @GetMapping("cache")
    @SaIgnore
    @Operation(summary = "测试缓存", description = "测试缓存")
    public ResultVo<String> cache() {
        StringBuffer sb = new StringBuffer();
        Collection<String> cacheNames = cacheManager.getCacheNames();
        for (String cacheName : cacheNames) {
            CaffeineCache cache = (CaffeineCache) cacheManager.getCache(cacheName);
            System.out.println(cache.getName());
            cache.getNativeCache().asMap().forEach((key, value) -> {
                sb.append(key).append(":").append(value).append("\n");
            });
            System.out.println("缓存:" + cache.getName());
        }
        return ResultVo.success(sb.toString());
    }

    @GetMapping("test")
    @SaIgnore
    @Operation(summary = "测试缓存", description = "测试缓存")
    public void test() {
        TemplateConfig templateConfig = new TemplateConfig("/templates", TemplateConfig.ResourceMode.CLASSPATH);
        TemplateEngine engine = TemplateUtil.createEngine(templateConfig);
        Map<String, Object> map = new HashMap<>();
        map.put("name", "张三");
        map.put("age", "36");
        map.put("desc", "测试");
        String template = engine.getTemplate("test.tpl").render(map);
        System.out.println(template);
    }
}
